package com.zh.harmony.startup;

import ohos.app.Context;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 移植 Android 的 JetPack Startup 应用组件初始化库
 */
@SuppressWarnings("WeakerAccess")
public final class AppInitializer {
    /**
     * 唯一实例
     */
    private static volatile AppInitializer sInstance;

    /**
     * 同步锁
     */
    private static final Object sLock = new Object();

    /**
     * 初始过的Initializer会放在这里，相当于一个缓存，重复初始化会直接返回实例
     */
    final Map<Class<?>, Object> mInitialized;

    /**
     * 应用上下文
     */
    final Context mContext;

    /**
     * 构造一个AppInitializer实例
     */
    AppInitializer(Context context) {
        mContext = context.getApplicationContext();
        mInitialized = new HashMap<>();
    }

    /**
     * 获取唯一实例
     */
    @SuppressWarnings("UnusedReturnValue")
    public static AppInitializer getInstance(Context context) {
        if (sInstance == null) {
            synchronized (sLock) {
                if (sInstance == null) {
                    sInstance = new AppInitializer(context);
                }
            }
        }
        return sInstance;
    }

    /**
     * 手动初始化一个组件
     */
    @SuppressWarnings("unused")
    public <T> T initializeComponent(Class<? extends Initializer<T>> component) {
        return doInitialize(component, new HashSet<>());
    }

    /**
     * 初始化
     */
    @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
    <T> T doInitialize(
            Class<? extends Initializer<?>> component,
            Set<Class<?>> initializing) {
        synchronized (sLock) {
            //不允许循环依赖
            if (initializing.contains(component)) {
                String message = String.format(
                        "Cannot initialize %s. Cycle detected.", component.getName()
                );
                throw new IllegalStateException(message);
            }
            Object result;
            //没有初始化，开始初始化
            if (!mInitialized.containsKey(component)) {
                initializing.add(component);
                try {
                    //反射构造Initializer
                    Object instance = component.getDeclaredConstructor().newInstance();
                    Initializer<?> initializer = (Initializer<?>) instance;
                    //获取依赖的组件列表
                    List<Class<? extends Initializer<?>>> dependencies =
                            initializer.dependencies();
                    //如果有的话，把依赖的组件也初始化
                    if (!dependencies.isEmpty()) {
                        for (Class<? extends Initializer<?>> clazz : dependencies) {
                            if (!mInitialized.containsKey(clazz)) {
                                doInitialize(clazz, initializing);
                            }
                        }
                    }
                    if (StartupLogger.DEBUG) {
                        StartupLogger.i(String.format("Initializing %s", component.getName()));
                    }
                    //通知初始化组件
                    result = initializer.create(mContext);
                    if (StartupLogger.DEBUG) {
                        StartupLogger.i(String.format("Initialized %s", component.getName()));
                    }
                    initializing.remove(component);
                    //放到缓存中
                    mInitialized.put(component, result);
                } catch (Throwable throwable) {
                    throw new StartupException(throwable);
                }
            } else {
                //初始化过了，直接返回
                result = mInitialized.get(component);
            }
            return (T) result;
        }
    }
}